import { assertEquals } from "@std/assert";
import { buildQuery } from "./main.ts";

interface UserDTO {
  name: string;
  age: number;
  email: string;
  address: string;
}

Deno.test("test eq", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "eq",
        value: "test",
      },
    ],
  });
  assertEquals(query, "name-op=eq&name=test");
});

Deno.test("test eq url encode", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "eq",
        value: "test|",
      },
    ],
  });
  assertEquals(query, "name-op=eq&name=test%7C");
});

Deno.test("test eq unicode value", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "eq",
        value: "南通",
      },
    ],
  });
  assertEquals(query, "name-op=eq&name=%E5%8D%97%E9%80%9A");
});

Deno.test("test ne", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "ne",
        value: "test",
      },
    ],
  });
  assertEquals(query, "name-op=ne&name=test");
});

Deno.test("test gt", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "gt",
        value: 18,
      },
    ],
  });
  assertEquals(query, "age-op=gt&age=18");
});

Deno.test("test ge", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "ge",
        value: 18,
      },
    ],
  });
  assertEquals(query, "age-op=ge&age=18");
});

Deno.test("test lt", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "lt",
        value: 18,
      },
      {
        label: "name",
        op: "ct",
        value: "john",
      },
    ],
  });
  assertEquals(query, "age-op=lt&age=18&name-op=ct&name=john");
});

Deno.test("test le", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "le",
        value: 18,
      },
    ],
  });
  assertEquals(query, "age-op=le&age=18");
});

Deno.test("test bt", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "bt",
        value: [18, 30],
      },
    ],
  });
  assertEquals(query, "age-op=bt&age-0=18&age-1=30");
});

Deno.test("test bt url encode", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "bt",
        value: ["18&", "30|"],
      },
    ],
  });
  assertEquals(query, "age-op=bt&age-0=18%26&age-1=30%7C");
});

Deno.test("test nb", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "nb",
        value: [18, 30],
      },
    ],
  });
  assertEquals(query, "age-op=nb&age-0=18&age-1=30");
});

Deno.test("test sw", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "sw",
        value: "John",
      },
    ],
  });
  assertEquals(query, "name-op=sw&name=John");
});

Deno.test("test ew", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "email",
        op: "ew",
        value: "example.com",
      },
    ],
  });
  assertEquals(query, "email-op=ew&email=example.com");
});

Deno.test("test ol", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "ol",
        value: ["John", "Jane", "Bob"],
      },
    ],
  });
  assertEquals(query, "name-op=ol&name-0=John&name-1=Jane&name-2=Bob");
});

Deno.test("test ol url encode", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "ol",
        value: ["John@", "Jane&", "Bob|"],
      },
    ],
  });
  assertEquals(query, "name-op=ol&name-0=John%40&name-1=Jane%26&name-2=Bob%7C");
});

Deno.test("test nk", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "nk",
        value: "stranger",
      },
    ],
  });
  assertEquals(query, "name-op=nk&name=stranger");
});

Deno.test("test il", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "il",
        value: [18, 25, 30],
      },
    ],
  });
  assertEquals(query, "age-op=il&age-0=18&age-1=25&age-2=30");
});

Deno.test("test ni", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "age",
        op: "ni",
        value: [18, 25, 30],
      },
    ],
  });
  assertEquals(query, "age-op=ni&age-0=18&age-1=25&age-2=30");
});

Deno.test("test nl", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "email",
        op: "nl",
      },
    ],
  });
  assertEquals(query, "email-op=nl");
});

Deno.test("test nn", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "email",
        op: "nn",
      },
    ],
  });
  assertEquals(query, "email-op=nn");
});

Deno.test("test ey", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "address",
        op: "ey",
      },
    ],
  });
  assertEquals(query, "address-op=ey");
});

Deno.test("test ny", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "address",
        op: "ny",
      },
    ],
  });
  assertEquals(query, "address-op=ny");
});

Deno.test("test at", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "at",
      },
    ],
  });
  assertEquals(query, "name-op=at");
});

Deno.test("test af", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "af",
      },
    ],
  });
  assertEquals(query, "name-op=af");
});

Deno.test("more than one field", () => {
  const query = buildQuery<UserDTO>({
    fields: [
      {
        label: "name",
        op: "eq",
        value: "test",
      },
      {
        label: "age",
        op: "gt",
        value: 18,
      },
    ],
  });
  assertEquals(query, "name-op=eq&name=test&age-op=gt&age=18");
});

Deno.test("fields params and group param", () => {
  const query = buildQuery<UserDTO>({
    fields: {
      A: [
        {
          label: "name",
          op: "eq",
          value: "test",
        },
        {
          label: "age",
          op: "gt",
          value: 18,
        },
      ],
      B: [
        {
          label: "address",
          op: "ct",
          value: "test",
        },
      ],
    },
    gexpr: "A|B",
  });
  assertEquals(
    query,
    "A.name-op=eq&A.name=test&A.age-op=gt&A.age=18&B.address-op=ct&B.address=test&gexpr=A%7CB",
  );
});

Deno.test("test tuple fields", () => {
  const query = buildQuery<UserDTO>({
    fields: [["name", "eq", "test"]],
  });
  assertEquals(query, "name-op=eq&name=test");
});

Deno.test("fields is undefined", () => {
  const query = buildQuery<UserDTO>({
    page: 1,
    size: 100,
  });
  assertEquals(query, "page=1&size=100");
});

Deno.test("test orderBy", () => {
  const query = buildQuery<UserDTO>({
    orderBy: [{ label: "name", order: "asc" }, { label: "age", order: "desc" }],
  });
  assertEquals(query, "orderBy=name:asc,age:desc");
});

Deno.test("orderBy extra generic", () => {
  const query = buildQuery<UserDTO, "id">({
    orderBy: [{ label: "name", order: "asc" }, { label: "id", order: "desc" }],
  });
  assertEquals(query, "orderBy=name:asc,id:desc");
});
